package com.hardson.toolkit.swing;

import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.List;

import javax.swing.AbstractButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JRadioButton;
import javax.swing.JRootPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.plaf.FontUIResource;
import javax.swing.text.JTextComponent;

import com.hardson.toolkit.util.ArrayUtil;
import com.hardson.toolkit.util.Lists;

/**
 * 提供对AWT,Swing有用的静态方法
 *
 * @author <a href="http:\\blog.csdn.net\dyhml">VirusCamp</a>
 */
public class SwingUtil {
	/**
	 * 由此类中方法使用的默认 java.awt.Toolkit
	 */
	public static final Toolkit toolkit = Toolkit.getDefaultToolkit();

	/**
	 * 将window全屏化,对Window,Frame,Dialog,JWindow,JFrame,JDialog有效
	 *
	 * @param window 全屏化的window
	 * @see Window,Frame,Dialog,JWindow,JFrame,JDialog
	 */
	public static void setSizeFullOfScreen(final Window window) {
		Dimension screenSize = toolkit.getScreenSize();
		window.setBounds(0, 0, screenSize.width, screenSize.height);
	}

	/**
	 * 将window设置在屏幕中间,对Window,Frame,Dialog,JWindow,JFrame,JDialog有效
	 *
	 * @param window 设置在屏幕中间的window
	 * @see Window,Frame,Dialog,JWindow,JFrame,JDialog
	 */
	public static void setToScreenCenter(final Window window) {
		Dimension screenSize = toolkit.getScreenSize();
		Dimension windowSize = window.getSize();
		if (windowSize.height > screenSize.height) {
			windowSize.height = screenSize.height;
		}
		if (windowSize.width > screenSize.width) {
			windowSize.width = screenSize.width;
		}
		window.setLocation((screenSize.width - windowSize.width) / 2,
				(screenSize.height - windowSize.height) / 2);
	}

	/**
	 * 设置全局字体
	 *
	 * @param font 全局字体
	 */
	public static void initGlobalFontSetting(final Font font) {
		FontUIResource fontRes = new FontUIResource(font);
		for (Enumeration<?> keys = UIManager.getDefaults().keys(); keys.hasMoreElements();) {
			Object key = keys.nextElement();
			Object value = UIManager.get(key);
			if (value instanceof FontUIResource) {
				UIManager.put(key, fontRes);
			}
		}
	}

	/**
	 * 在Component上设置光标(Cursor)
	 *
	 * @param c     在此Component上设置光标(Cursor)
	 * @param image 设置的光标(Cursor)图案
	 */
	public static void setCursor(final Component c, final Image image) {
		Cursor cursor = toolkit.createCustomCursor(image, new Point(0, 0), null);
		c.setCursor(cursor);
	}

	/**
	 * 设置全局LookAndFeel,此后建立的Swing部件使用此LookAndFeel
	 *
	 * @param lafstr 设置的LookAndFeel
	 * @return 0:设置成功,1:设置失败
	 */
	public static int setGlobalLookAndFeel(final String lafstr) {
		try {
			UIManager.setLookAndFeel(lafstr);
			return 0;
		} catch (Exception e) {
			return 1;
		}
	}

	/**
	 * 此后建立的JFrame,JDialog是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	private static boolean isUndecorated = false;

	/**
	 * 返回此后建立的JFrame,JDialog是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 *
	 * @return 此后建立的JFrame,JDialog是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	public static boolean isUndecorated() {
		return isUndecorated;
	}

	/**
	 * 设置此后建立的JFrame,JDialog是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 *
	 * @param 是否此后建立的JFrame,JDialog使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	public static void setUndecorated(final boolean undecorated) {
		LookAndFeel laf = UIManager.getLookAndFeel();
		SwingUtil.isUndecorated = undecorated;
		JFrame.setDefaultLookAndFeelDecorated(undecorated && laf.getSupportsWindowDecorations());
		JDialog.setDefaultLookAndFeelDecorated(undecorated && laf.getSupportsWindowDecorations());
	}

	/**
	 * 设置JFrame是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 *
	 * @param 是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	public static void setUndecorated(final JFrame frame, final boolean undecorated) {
		if (frame.isDisplayable()) {
			frame.dispose();
		}
		frame.setUndecorated(undecorated && UIManager.getLookAndFeel().getSupportsWindowDecorations());
		JRootPane jRootPane = frame.getRootPane();
		jRootPane.setWindowDecorationStyle(jRootPane.getWindowDecorationStyle());
		if (frame.isDisplayable()) {
			frame.setVisible(true);
		}
	}

	/**
	 * 设置JDialog是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 *
	 * @param 是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	public static void setUndecorated(final JDialog dialog, final boolean undecorated) {
		if (dialog.isDisplayable()) {
			dialog.dispose();
		}
		dialog.setUndecorated(undecorated && UIManager.getLookAndFeel().getSupportsWindowDecorations());
		JRootPane jRootPane = dialog.getRootPane();
		jRootPane.setWindowDecorationStyle(jRootPane.getWindowDecorationStyle());
		if (dialog.isDisplayable()) {
			dialog.setVisible(true);
		}
	}

	/**
	 * 更新本程序建立的所有JFrame的LookAndFeel
	 */
	public static void updateUI() {
		Frame[] frames = Frame.getFrames();
		for (int i = 0; i < frames.length; i++) {
			updateUI(frames[i]);
		}
	}

	/**
	 * 更新Component的LookAndFeel
	 *
	 * @param target 操作对象
	 */
	public static void updateUI(final Component target) {
		if (target instanceof JFrame) {
			updateUI((JFrame) target, isUndecorated);
		}
		if (target instanceof JDialog) {
			updateUI((JDialog) target, isUndecorated);
		}
		SwingUtilities.updateComponentTreeUI(target);
	}

	/**
	 * 更新JFrame的LookAndFeel,改变JFrame的边框,标题
	 *
	 * @param frame       操作对象
	 * @param undecorated 是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	public static void updateUI(final JFrame frame, final boolean undecorated) {
		setUndecorated(frame, undecorated);
		SwingUtilities.updateComponentTreeUI(frame);
	}

	/**
	 * 更新JDialog的LookAndFeel,改变JDialog的边框,标题
	 *
	 * @param dialog      操作对象
	 * @param undecorated 是否使用LookAndFeel的窗口装饰(标题栏,边框等)
	 */
	public static void updateUI(final JDialog dialog, final boolean undecorated) {
		setUndecorated(dialog, undecorated);
		SwingUtilities.updateComponentTreeUI(dialog);
	}

	/**
	 * 设置下拉组件JComboBox不可改变选项。
	 *
	 * @param box
	 */
	public static void setSelectable(final JComboBox<?> box, final boolean selectable) {
		if (!selectable) {
			box.addItemListener(new MyItemListener(box));
		} else {
			ItemListener listeners[] = box.getItemListeners();
			if (!ArrayUtil.isEmpty(listeners)) {
				Arrays.stream(listeners).forEach(box::removeItemListener);
			}
		}
	}

	private static class MyItemListener implements ItemListener {

		private Object oldObj = null;
		private JComboBox<?> box = null;

		MyItemListener(JComboBox<?> box) {
			this.box = box;
			box.addFocusListener(new FocusAdapter() {
				@Override
				public void focusGained(final FocusEvent e) {
					MyItemListener.this.oldObj = box.getSelectedItem();
				}
			});
		}

		@Override
		public void itemStateChanged(final ItemEvent e) {
			int state = e.getStateChange();
			if (state == ItemEvent.SELECTED) {
				this.box.removeItemListener(this);
				this.box.setSelectedItem(this.oldObj);
				this.box.addItemListener(this);
			}
		}
	}

	/**
	 * 根据组件查找包含该组件的JFrame容器。
	 *
	 * @param comp
	 * @return
	 */
	public static Window getParentWindow(final Component comp) {
		if (comp == null) {
			return JOptionPane.getRootFrame();
		}
		if (isWindow(comp)) {
			return (Window) comp;
		}
		return getParentWindow(comp.getParent());
	}

	public static Frame getParentFrame(final Component comp) {
		Window window = getParentWindow(comp);
		return (window instanceof Frame) ? (Frame) window : null;
	}

	public static boolean isWindow(final Component comp) {
		return (comp instanceof Frame) || (comp instanceof Dialog);
	}

	/**
	 * 设置指定容器内的组件的状态为可用或不可用
	 *
	 * @param container
	 * @param enable
	 */
	public static void setComponentState(final Container container, final boolean enable,
			final List<Component> excludeComps) {
		Component[] comps = container.getComponents();
		for (Component aComp : comps) {
			if (excludeComps.contains(aComp)) {
				continue;
			}
			if (aComp instanceof JTextComponent) {
				((JTextComponent) aComp).setEditable(enable);
				aComp.setBackground(Color.WHITE);
			} else if (aComp instanceof JComboBox) {
				// ((JComboBox<?>) aComp).setEnabled(false);
				final JComboBox<?> aBox = (JComboBox<?>) aComp;
				setSelectable(aBox, enable);
			} else if (aComp instanceof AbstractButton) {
				aComp.setEnabled(enable);
			} else if (aComp instanceof Container) {
				setComponentState((Container) aComp, enable, excludeComps);
			}
		}
	}

	/**
	 * 设置指定容器内的组件的状态为可用或不可用
	 *
	 * @param container
	 * @param enable
	 */
	public static void setComponentState(final Container container, final boolean enable) {
		setComponentState(container, enable, Lists.EMPTY_LIST());
	}

	/**
	 * 清空指定容器内的表单数据
	 *
	 * @param container
	 */
	public static void reSetFormComponent(final Container container) {
		Component[] comps = container.getComponents();
		for (Component aComp : comps) {
			if (aComp instanceof JTextComponent) {
				((JTextComponent) aComp).setText("");
			} else if (aComp instanceof JComboBox) {
				final JComboBox<?> aBox = (JComboBox<?>) aComp;
				aBox.setSelectedIndex(-1);
			} else if (aComp instanceof JCheckBox) {
				final JCheckBox aBox = (JCheckBox) aComp;
				aBox.setSelected(false);
			} else if (aComp instanceof JRadioButton) {
				final JRadioButton aBox = (JRadioButton) aComp;
				aBox.setSelected(false);
			} else if (aComp instanceof Container) {
				reSetFormComponent((Container) aComp);
			}
		}
	}

	/**
	 * 光标移至错误字段并全选字段内容
	 *
	 * @param errorFld
	 */
	public static void showErrorField(final JTextField errorFld) {
		errorFld.requestFocus();
		errorFld.setSelectionStart(0);
		errorFld.setSelectionEnd(errorFld.getText().length());
	}

	/**
	 * 滚动到表格的最后一行
	 *
	 * @param table
	 */
	public static void goLast(JTable table) {
		int row = table.getRowCount() - 1;
		if (row < 0) {
			return;
		}
		table.setRowSelectionInterval(row, row);
		Rectangle rect = table.getCellRect(row, row, true);
		table.scrollRectToVisible(rect);
	}
}
